﻿using System;
using System.Collections.Generic;

namespace MessagePack.Formatters
{
	// Token: 0x0200000D RID: 13
	public abstract class CollectionFormatterBase<TElement, TIntermediate, TEnumerator, TCollection> : IMessagePackFormatter<TCollection> where TEnumerator : IEnumerator<TElement> where TCollection : IEnumerable<TElement>
	{
		// Token: 0x06000023 RID: 35 RVA: 0x000028B0 File Offset: 0x00000CB0
		public int Serialize(ref byte[] bytes, int offset, TCollection value, IFormatterResolver formatterResolver)
		{
			if (value == null)
			{
				return MessagePackBinary.WriteNil(ref bytes, offset);
			}
			TElement[] array = value as TElement[];
			if (array != null)
			{
				int num = offset;
				IMessagePackFormatter<TElement> formatterWithVerify = formatterResolver.GetFormatterWithVerify<TElement>();
				offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, array.Length);
				foreach (TElement value2 in array)
				{
					offset += formatterWithVerify.Serialize(ref bytes, offset, value2, formatterResolver);
				}
				return offset - num;
			}
			int num2 = offset;
			IMessagePackFormatter<TElement> formatterWithVerify2 = formatterResolver.GetFormatterWithVerify<TElement>();
			int? count = this.GetCount(value);
			if (count != null)
			{
				offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, count.Value);
				TEnumerator sourceEnumerator = this.GetSourceEnumerator(value);
				try
				{
					while (sourceEnumerator.MoveNext())
					{
						offset += formatterWithVerify2.Serialize(ref bytes, offset, sourceEnumerator.Current, formatterResolver);
					}
				}
				finally
				{
					sourceEnumerator.Dispose();
				}
				return offset - num2;
			}
			int num3 = offset;
			int num4 = 0;
			int num5 = 0;
			offset += 3;
			TEnumerator sourceEnumerator2 = this.GetSourceEnumerator(value);
			try
			{
				while (sourceEnumerator2.MoveNext())
				{
					num4++;
					int num6 = formatterWithVerify2.Serialize(ref bytes, offset, sourceEnumerator2.Current, formatterResolver);
					num5 += num6;
					offset += num6;
				}
			}
			finally
			{
				sourceEnumerator2.Dispose();
			}
			int arrayHeaderLength = MessagePackBinary.GetArrayHeaderLength(num4);
			if (arrayHeaderLength != 3)
			{
				if (arrayHeaderLength == 1)
				{
					offset -= 2;
				}
				else
				{
					offset += 2;
				}
				MessagePackBinary.EnsureCapacity(ref bytes, offset, arrayHeaderLength);
				Buffer.BlockCopy(bytes, num3 + 3, bytes, num3 + arrayHeaderLength, num5);
			}
			MessagePackBinary.WriteArrayHeader(ref bytes, num3, num4);
			return offset - num2;
		}

		// Token: 0x06000024 RID: 36 RVA: 0x00002A98 File Offset: 0x00000E98
		public TCollection Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize)
		{
			if (MessagePackBinary.IsNil(bytes, offset))
			{
				readSize = 1;
				return default(TCollection);
			}
			int num = offset;
			IMessagePackFormatter<TElement> formatterWithVerify = formatterResolver.GetFormatterWithVerify<TElement>();
			int num2 = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize);
			offset += readSize;
			TIntermediate tintermediate = this.Create(num2);
			for (int i = 0; i < num2; i++)
			{
				this.Add(tintermediate, i, formatterWithVerify.Deserialize(bytes, offset, formatterResolver, out readSize));
				offset += readSize;
			}
			readSize = offset - num;
			return this.Complete(tintermediate);
		}

		// Token: 0x06000025 RID: 37 RVA: 0x00002B24 File Offset: 0x00000F24
		protected virtual int? GetCount(TCollection sequence)
		{
			ICollection<TElement> collection = sequence as ICollection<TElement>;
			if (collection != null)
			{
				return new int?(collection.Count);
			}
			return null;
		}

		// Token: 0x06000026 RID: 38
		protected abstract TEnumerator GetSourceEnumerator(TCollection source);

		// Token: 0x06000027 RID: 39
		protected abstract TIntermediate Create(int count);

		// Token: 0x06000028 RID: 40
		protected abstract void Add(TIntermediate collection, int index, TElement value);

		// Token: 0x06000029 RID: 41
		protected abstract TCollection Complete(TIntermediate intermediateCollection);
	}
}
